﻿using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace BikeSharing.Clients.Core.Animations.Base
{
    public abstract class AnimationBase : BindableObject
    {
        private bool _isRunning = false;

        public static readonly BindableProperty TargetProperty =
        BindableProperty.Create("Target", typeof(VisualElement), typeof(AnimationBase), null,
        propertyChanged: (bindable, oldValue, newValue) =>
        ((AnimationBase)bindable).Target = (VisualElement)newValue);

        public VisualElement Target
        {
            get { return (VisualElement)GetValue(TargetProperty); }
            set { SetValue(TargetProperty, value); }
        }

        public static readonly BindableProperty DurationProperty =
            BindableProperty.Create("Duration", typeof(string), typeof(AnimationBase), "1000",
                propertyChanged: (bindable, oldValue, newValue) =>
                ((AnimationBase)bindable).Duration = (string)newValue);

        public string Duration
        {
            get { return (string)GetValue(DurationProperty); }
            set { SetValue(DurationProperty, value); }
        }

        public static readonly BindableProperty EasingProperty =
            BindableProperty.Create("Easing", typeof(EasingType), typeof(AnimationBase), EasingType.Linear,
            propertyChanged: (bindable, oldValue, newValue) =>
            ((AnimationBase)bindable).Easing = (EasingType)newValue);

        public EasingType Easing
        {
            get { return (EasingType)GetValue(EasingProperty); }
            set { SetValue(EasingProperty, value); }
        }

        public static readonly BindableProperty RepeatForeverProperty =
          BindableProperty.Create("RepeatForever", typeof(bool), typeof(AnimationBase), false,
              propertyChanged: (bindable, oldValue, newValue) =>
              ((AnimationBase)bindable).RepeatForever = (bool)newValue);

        public bool RepeatForever
        {
            get { return (bool)GetValue(RepeatForeverProperty); }
            set { SetValue(RepeatForeverProperty, value); }
        }

        public static readonly BindableProperty DelayProperty =
           BindableProperty.Create("Delay", typeof(int), typeof(AnimationBase), 0,
               propertyChanged: (bindable, oldValue, newValue) =>
               ((AnimationBase)bindable).Delay = (int)newValue);

        public int Delay
        {
            get { return (int)GetValue(DelayProperty); }
            set { SetValue(DelayProperty, value); }
        }

        protected abstract Task BeginAnimation();

        public async Task Begin()
        {
			try
			{

				if (!_isRunning)
				{
					_isRunning = true;

					await InternalBegin()
						.ContinueWith(t => t.Exception, TaskContinuationOptions.OnlyOnFaulted)
						.ConfigureAwait(false);
				}
			}
            catch (TaskCanceledException)
            {
            }
			catch (Exception ex)
			{
				Debug.WriteLine($"Exception in animation {ex}");
			}
        }

        protected abstract Task ResetAnimation();

        public async Task Reset()
        {
            await ResetAnimation();
        }

		private async Task InternalBegin()
		{
			if (Delay > 0)
			{
				await Task.Delay(Delay);
			}

			if (!RepeatForever)
			{
				await BeginAnimation();
			}
			else
			{
				do
				{
					await BeginAnimation();
					await ResetAnimation();
				} while (RepeatForever);
			}
		}
    }
}